package com.astrocsr.business;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.astrocsr.common.Constants;
import com.astrocsr.common.helper.EncryptionHelper;
import com.astrocsr.domain.bean.TblGroup;
import com.astrocsr.domain.bean.TblGroupAccount;
import com.astrocsr.domain.bean.TblUser;
import com.astrocsr.domain.condition.SecCondition;
import com.astrocsr.domain.condition.UserCondition;
import com.astrocsr.domain.db.PagingInfo;
import com.astrocsr.domain.db.SearchResult;
import com.astrocsr.domain.web.Item;
import com.astrocsr.domain.web.UserInfo;

@Service("userManager")
@Transactional(value = "transactionManager", propagation = Propagation.REQUIRED)
public class UserManager extends BaseManager {

	/**
	 * Get user by email
	 */
	public UserInfo getUserByEmail(String email) throws Exception {
		TblUser tblUser = getUserDAO().findByEmail(email);
		UserInfo userInfo = null;
		if (tblUser != null && tblUser.getUserId() != null) {
			userInfo = new UserInfo();
			BeanUtils.copyProperties(tblUser, userInfo);
		}
		return userInfo;

	}
	
	public UserInfo getUserById(Long id) throws Exception {
		TblUser tblUser = getUserDAO().findById(id);
		UserInfo userInfo = null;
		if (tblUser != null) {
			userInfo = new UserInfo();
			BeanUtils.copyProperties(tblUser, userInfo);
		}
		return userInfo;

	}
	/**
	 * List all users
	 */
	public SearchResult<UserInfo> listUser(UserInfo userInfo, PagingInfo pagingInfo) throws Exception {
		return listUser(null, userInfo, pagingInfo);
	}
	/**
	 * List users with parent group
 	 */
	public SearchResult<UserInfo> listUser(String currentGroup, UserInfo userInfo, PagingInfo pagingInfo) throws Exception {

		SearchResult<UserInfo> userList = null;
		
		UserCondition condition = null;
		if (userInfo != null) {
			condition = new UserCondition();
			condition.setEmail(userInfo.getEmail());
			condition.setGroupCode(userInfo.getGroupCode());
		}
		if (StringUtils.isNotBlank(currentGroup)) {
			if (condition == null) condition = new UserCondition();
			// get all groups that are children of currentGroup
			List<TblGroup> groupList = getGroupDAO().listGroupByParentCode(new SecCondition(currentGroup), null, false);
			if (groupList != null && !groupList.isEmpty()) {
				List<String> groupCodeList = new ArrayList<String>();
				for (TblGroup tblGroup : groupList) {
					groupCodeList.add(tblGroup.getGroupCode());
				}
				condition.setGroupCodeList(groupCodeList);
			} else {
				// in case, don't have any sub group
				return null;
			}
		}
		
		SearchResult<TblUser>  tblUserList = getUserDAO().listTblUser(condition, pagingInfo); 

		if (tblUserList != null && tblUserList.size() > 0) {
			userList = new SearchResult<UserInfo>();
			UserInfo info = null;
			for (TblUser bean : tblUserList) {
				info = new UserInfo();
				BeanUtils.copyProperties(bean, info);
				userList.add(info);
			}
			
			userList.setPagingInfo(tblUserList.getPagingInfo());
		}

		return userList;
	}
	
	/**
	 * Check existed user
	 */
	public boolean checkExistedUser(String email) throws Exception {

		return getUserDAO().checkExistedUser(email); 
	}

	/**
	 * This method insert data into USER table
	 */
	public void addUser(UserInfo user) throws Exception {
		if (user != null) {
			TblUser tblUser = new TblUser();
			
			tblUser.setEmail(user.getEmail());
			tblUser.setStatus(user.getStatus());
			tblUser.setGroupCode(user.getGroupCode());
			// MD5 password
			tblUser.setPassword(EncryptionHelper.encodeMD5(user.getPassword()));
			tblUser.setLocked(user.getLocked());
			tblUser.setEnabled(user.getEnabled());
			tblUser.setCreatedBy(user.getCreatedBy());
			tblUser.setCreatedDate(new Date());
			tblUser.setUpdatedDate(new Date());
			// Call DAO layer to insert user into database
			getUserDAO().addTblUser(tblUser);
		}		
	}

	/**
	 * This method update data into USER table
	 */
	public void updateUser(UserInfo user) throws Exception {
		if (user != null) {
			TblUser tblUser = new TblUser();
			
			tblUser.setEmail(user.getEmail());
			tblUser.setStatus(user.getStatus());
			// MD5 password
			tblUser.setPassword(EncryptionHelper.encodeMD5(user.getPassword()));
			tblUser.setUpdatedDate(new Date());
			tblUser.setUpdatedBy(user.getUpdatedBy());
			// Call DAO layer to insert user into database
			getUserDAO().updateTblUser(tblUser);
		}		
	}
	
	public void resetUser(Long userId, String group, String strUserPwd, boolean enable, boolean lock, String updateBy, List<String> returnMsg) throws Exception {

		try {
			TblUser tblUser = new TblUser();
			
			TblUser bean = getUserDAO().findById(userId);

			if (returnMsg == null) 
				returnMsg = new ArrayList<String>();
			
			//1 Group
			if (group != null & !StringUtils.isBlank(group) && !group.equals(bean.getGroupCode())) {
				tblUser.setGroupCode(group);
				returnMsg.add("group");
			}
			//2 Password
			if (!StringUtils.isBlank(strUserPwd)) {
				tblUser.setPassword(strUserPwd);
				returnMsg.add("pwd");

			}
			//3 Enabled
			if ((Constants.YES.equals(bean.getEnabled()) && !enable) || (!Constants.YES.equals(bean.getEnabled()) && enable)) {
				tblUser.setEnabled(enable?Constants.YES: Constants.NO);
				returnMsg.add(enable? "enable":"disable");
			}
			//4 Locked
			if ((Constants.YES.equals(bean.getLocked()) && !lock) || (!Constants.YES.equals(bean.getLocked()) && lock)) {
				tblUser.setLocked(lock?Constants.YES: Constants.NO);
				returnMsg.add(lock?"lock":"unlock");
			}

			tblUser.setUserId(userId);
			tblUser.setUpdatedDate(new Date());
			tblUser.setUpdatedBy(updateBy);
			
			// Call DAO layer to insert user into database
			getUserDAO().resetTblUser(tblUser);
			
		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
	 * Change password
	 */
	public void updatePassword(UserInfo userInfo) throws Exception {
		
		TblUser tblUser = new TblUser();
		tblUser.setUserId(userInfo.getUserId());
		tblUser.setEmail(userInfo.getEmail());
		tblUser.setPassword(EncryptionHelper.encodeMD5(userInfo.getPassword()));
		tblUser.setUpdatedDate(new Date());
		getUserDAO().updatePassword(tblUser);
		
	}
	
	/**
	 * Lock User
	 */
	public void lockUser(String email) throws Exception {
		getUserDAO().lockUser(email);
	}

	/**
	 * update Last Login
	 */
	public void updateLastLogin(String email) throws Exception {
		getUserDAO().updateLastLogin(email);
	}

	/**
	 * This method delete data into USER table
	 */
	public void deleteUser(Long userId) throws Exception {
		if (userId != null) {
			// Call DAO layer to delete user into database
			getUserDAO().deleteTblUser(userId);
		}		
	}

	/**
	 * Build date
	 */
	public List<Item> buildMonths(int num) throws Exception {
		List<Item> list = new ArrayList<Item>();
		Calendar cal = Calendar.getInstance();
		Item item = null;
		for (int i = 0; i < num; i++) {
			item = new Item();
			item.setItemName(cal.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.ENGLISH) + "-" + cal.get(Calendar.YEAR));
			item.setItemValue((cal.get(Calendar.MONTH)+1) + "-" + cal.get(Calendar.YEAR));
			cal.add(Calendar.MONTH, -1);
			list.add(item);
		}
		return list;
	}
	
	/* Account */
	/**
	 * Check existed assign
	 */
	public boolean checkAssignedAccount(String selectedAccountNo, String selectedGroupNo) throws Exception {

		return getGroupAccountDAO().checkAssignedAccount(selectedAccountNo, selectedGroupNo); 
	}
	
	/**
	 * This method insert data into GROUP_ACCOUNT table
	 */
	public void addGroupAccount(String accountNo, String groupCode, String loginId) throws Exception {
		if (StringUtils.isNotBlank(accountNo) && StringUtils.isNotBlank(groupCode)) {
			TblGroupAccount tblGroupAccount = new TblGroupAccount();
			
			tblGroupAccount.setAccountNo(accountNo);
			tblGroupAccount.setGroupCode(groupCode);
			
			tblGroupAccount.setCreatedBy(loginId);
			tblGroupAccount.setUpdatedBy(loginId);
			tblGroupAccount.setCreatedDate(new Date());
			tblGroupAccount.setUpdatedDate(new Date());
			// Call DAO layer to insert user into database
			getGroupAccountDAO().addGroupAccount(tblGroupAccount);
		}		
	}
	
	/**
	 * check if group of email is under the current Group or not
	 */
	public boolean checkAllowedGroup(String group, String currentGroup) throws Exception {
		boolean res = false;

		if (group != null && !group.equals(currentGroup)) {
			List<TblGroup> hieGroupList = getGroupDAO().listGroupHierarchy(currentGroup);
			if (hieGroupList != null && hieGroupList.size() > 0) {
				for (TblGroup tblGroup : hieGroupList) {
					if (group != null && group.equals(tblGroup.getGroupCode())) {
						res = true;
						break;
					}
				}
			}
		}
		return res;
	}
}